﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml.Linq;

namespace StockCrawler
{
    public class PriceInfoCrawler
    {
        public void Run()
        {
            Console.WriteLine("Retrieving price history data...");
            
            if (CrawlingContext.Current.StockList != null)
            {
                foreach (var symbol in CrawlingContext.Current.StockList)
                {
                    DoCrawling(symbol);
                }
            }

            Console.WriteLine("Finished retrieving price history data.");
        }

        private void DoCrawling(string symbol)
        {
            IList<PriceHistory> priceHistoryList = RetrievePriceHistoryData(symbol);
            SavePriceHistoryData(priceHistoryList);            
        }

        private IList<PriceHistory> RetrievePriceHistoryData(string symbol)
        {
            String rawData = RetrieveRawData(symbol);

            return ParseData(symbol, rawData);            
        }

        private string RetrieveRawData(string symbol)
        {
            try
            {
                HttpWebRequest myWebRequest = (HttpWebRequest)WebRequest.Create(String.Format("http://cafef.vn/Lich-su-giao-dich-Symbol-{0}/Trang-1-0-tab-1.chn", symbol.ToUpper()));
                using (HttpWebResponse siteResponse = (HttpWebResponse)myWebRequest.GetResponse())
                {
                    using (Stream streamResponse = siteResponse.GetResponseStream())
                    {
                        using (StreamReader reader = new StreamReader(streamResponse, Encoding.UTF8))
                        {
                            var stockData = reader.ReadToEnd();
                            stockData = stockData.Replace(Environment.NewLine, String.Empty)
                                                 .Replace("&nbsp;", String.Empty);

                            Regex regex = new Regex(@"\<tr id="".+rptData((?!(\<\/tr\>)).)*(\<\/tr\>)"); //.*"".+\<\/tr\>");
                            //Regex regex = new Regex(@"\<trid=""ctl18_rptData((?!(\<\/tr\>)).)*(\<\/tr\>)"); //.*"".+\<\/tr\>");
                            var stockInfoList = regex.Matches(stockData);

                            if (stockInfoList.Count > 0)
                            {
                                return stockInfoList[stockInfoList.Count - 1].Value;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }

            return string.Empty;
        }

        private IList<PriceHistory> ParseData(string symbol, string rawData)
        {
            if (String.IsNullOrWhiteSpace(rawData))
            {
                return null;
            }

            var priceData = RefineData(rawData);

            XDocument document = XDocument.Parse(priceData);
            IList<PriceHistory> priceHistoryList = new List<PriceHistory>();

            foreach (var transactionItem in document.Root.Elements("tr"))
            {
                var valueList = transactionItem.Elements("td").ToList();
                priceHistoryList.Add(new PriceHistory()
                {
                    Symbol = symbol.ToUpper(),
                    TransactionDate = CrawlingUtility.ParseDate(valueList[0].Value),
                    ClosedPrice = CrawlingUtility.ParsePrice(valueList[1].Value),
                    Change = CrawlingUtility.ParseNumber(valueList[3].Value),
                    BasicPrice = CrawlingUtility.ParsePrice(valueList[5].Value),
                    OpeningPrice = CrawlingUtility.ParsePrice(valueList[6].Value),
                    MaxPrice = CrawlingUtility.ParsePrice(valueList[7].Value),
                    MinPrice = CrawlingUtility.ParsePrice(valueList[8].Value),
                    MatchingVolume = CrawlingUtility.ParseVolume(valueList[9].Value),
                    MatchingValue = CrawlingUtility.ParseNumber(valueList[10].Value),
                    PutthroughVolume = CrawlingUtility.ParseVolume(valueList[11].Value),
                    PutthroughValue = CrawlingUtility.ParseNumber(valueList[12].Value)
                });
            }

            return priceHistoryList.OrderByDescending(p => p.TransactionDate).ToList();
        }

        private string RefineData(string rawData)
        {
            Regex regex = new Regex(@"\<span((?!(\<\/span\>)).)*\>");
            rawData = regex.Replace(rawData, String.Empty);
            regex = new System.Text.RegularExpressions.Regex(@"\<\/span\>");
            rawData = regex.Replace(rawData, String.Empty);
            regex = new Regex(@"\<img((?!(\>)).)*\>");
            rawData = regex.Replace(rawData, String.Empty);
            regex = new Regex(@"\([-\.\d]+\s%\)");
            rawData = regex.Replace(rawData, String.Empty);

            rawData = String.Format("<PriceData>{0}</PriceData>", rawData);

            return rawData;
        }  

        private void SavePriceHistoryData(IList<PriceHistory> priceHistoryList)
        {
            if (priceHistoryList != null && priceHistoryList.Count > 0)
            {
                using (var context = new StockBiz())
                {
                    foreach (var priceHistory in priceHistoryList)
                    {
                        if (context.PriceHistories.Where(p
                                                            =>
                                                                p.Symbol == priceHistory.Symbol
                                                                       && p.TransactionDate == priceHistory.TransactionDate
                                                        ).Count() <= 0)
                        {
                            priceHistory.ID = Guid.NewGuid();
                            context.PriceHistories.AddObject(priceHistory);
                        }
                        else
                        {
                            break;
                        }
                    }

                    context.SaveChanges();
                }
            }
        }
    }
}
